# 公共方法库 基础包

"""
代码规范
函数命名：小写下划线
局部变量：小写下划线
类名：大驼峰
减少一切递归，和无效时空复杂度
目录
V1.0版本中暂时不做分类，只写常用方法
"""
from constants import *


# 判断变量类型
def show_data_type(variate: object) -> str:
    """
    :param variate: 任意变量
    :return: 返回变量类型
    """
    data_type = None
    if isinstance(variate, int):
        data_type = "int"
    elif isinstance(variate, str):
        data_type = "str"
    elif isinstance(variate, float):
        data_type = "float"
    elif isinstance(variate, list):
        data_type = "list"
    elif isinstance(variate, tuple):
        data_type = "tuple"
    elif isinstance(variate, dict):
        data_type = "dict"
    elif isinstance(variate, set):
        data_type = "set"
    else:
        data_type = type(variate)
    return data_type


# 列表转字典
def list_to_dict(input_list_value: list, input_list_key: list = []) -> dict:
    """
    :param input_list_value: 需要转换的列表
    :param input_list_key: 可选，需要转换成字典的键列表，如果没有默认键为从0开始的数字列表
    :return: 输出一个字典
    """
    result_dict = EMPTY_DICT
    if input_list_key:
        for index in range(len(input_list_value)):
            try:
                result_dict[input_list_key[index]] = input_list_value[index]
            except IndexError:
                raise IndexError('输入了错误的键数组.')
    else:
        count = INIT_INT
        for item in input_list_value:
            result_dict[count] = item
            count += 1
    return result_dict


# 字典键值互换
def key_value_switch(input_dict: dict) -> dict:
    '''
    :param input_dict:输入字典
    :return: 键值对互换后的字典
    '''
    result_dict = EMPTY_DICT
    if show_data_type(input_dict) != 'dict':
        raise TypeError("输入的不是字典")
    else:
        for key, val in input_dict.items():
            if val in result_dict:
                raise KeyError("字典有重复的值")
            else:
                result_dict[val] = key
    return result_dict


# 字典根据值反找对应的键
def find_key_by_value(input_dict: dict, specific_value):
    """
    :param input_dict: 输入的字典
    :param specific_value: 特定的值
    :return: 找到的键，如果不存在该值返回false
    """
    result = EMPTY_LIST
    if show_data_type(input_dict) != 'dict':
        raise TypeError("输入的不是字典")
    for key, val in input_dict.items():
        if val == specific_value:
            result.append(val)
    if len(result) == 0:
        return False
    elif len(result) == 1:
        return result[0]
    else:
        return result


# 频率统计
def frequency_count(input_contant) -> dict:
    """
    :param input_contant: 待统计字符串或列表
    :return:频率字典
    """
    result = EMPTY_DICT
    try:
        for char in input_contant:
            result[char] = result.get(char, 0) + 1
        return result
    except TypeError:
        raise TypeError("输入的不是可迭代对象")


# 文本标点符号清理
def clean_str(input_str: str) -> str:
    """
    :param input_str: 待清理字符串
    :return: 清理后字符串
    """
    result_str = EMPTY_STRING
    for char in input_str:
        if char not in SPECIAL_SYMBOLS_COMMON:
            result_str += char
    return result_str


# 字符串列表内容查找
def list_of_str_find_element(input_list: list, target_element: str, mode: int = SEARCH_MODE["EXACT"]) -> list:
    """
    :param input_list: 输入列表
    :param target_element: 带查找内容
    :param mode: 查询模式 0为精确查找 1为模糊查找
    :return: 查找结果
    """
    result_list = EMPTY_LIST
    if show_data_type(input_list) != 'list':
        raise TypeError("输入的不是列表")
    if mode not in SEARCH_MODE.values():
        raise ValueError("没有此类模式")
    if mode == SEARCH_MODE["EXACT"]:
        for item in input_list:
            if item == target_element:
                result_list.append(item)
    if mode == SEARCH_MODE["FUZZY"]:
        for item in input_list:
            if target_element in item:
                result_list.append(item)
    return result_list


# 字典列表同字段值求和统计
def sum_field_value(data_list: list, field):
    """
    :param data_list: 字典列表，每个字典都包含field字段
    :param field: 需要求和的字段名
    :return: 字段的总和
    """
    field_value_sum = 0
    for data in data_list:
        if not show_data_type(data) == "dict":
            raise TypeError("data_list中的元素必须为字典")
        if field not in data:
            raise ValueError("data_list中的字典缺少{}字段".format(field))
        field_value = data[field]
        if show_data_type(field_value) != "int" and show_data_type(field_value) != "float":
            raise TypeError("{}字段的值必须为数字类型".format(field))
        field_value_sum += field_value
    return field_value_sum


# 字典列表同字段摘取转列表
def extract_field_to_list(data_list: list, field):
    """
    :param data_list: 字典列表，[dict, ...]
    :param field: 需要提取的字段名称，str
    :return: 提取后的字段值列表，list
    """
    extracted_field_values = EMPTY_LIST
    for data in data_list:
        if field not in data:
            raise KeyError(f"field '{field}' not found in dictionary")
        extracted_field_values.append(data[field])
    return extracted_field_values


# 将列表元素按给定个数分组，余下的元素单独成一组，形成一个新的二维列表
def list_group_elements(elements, group_size):
    """
    参数：
    :param elements: list, 需要分组的元素列表
    :param group_size: int, 每组元素个数
    :return: list, 二维列表，每一维代表一个分组
    """
    if not isinstance(elements, list):
        raise TypeError("elements 必须是列表")
    if not isinstance(group_size, int):
        raise TypeError("group_size 必须是整数")
    if group_size < 1:
        raise ValueError("group_size 必须大于等于 1")
    result = []
    for i in range(0, len(elements), group_size):
        result.append(elements[i:i + group_size])
    if len(elements) % group_size != 0:
        result.append(elements[len(elements) - len(elements) % group_size:])
    return result


# 列表去重
def remove_duplicates(data: list) -> list:
    """
    :param data: list，待处理的列表
    :return: list，处理后的列表，不含重复项
    """
    if not isinstance(data, list):
        raise TypeError("data必须是list类型")
    return list(set(data))


# 最多次出现
def most_frequent_item(lst):
    """
    参数:
    :param lst (list): 要计算的列表
    :return 返回出现次数最多的项
    """
    if not isinstance(lst, list):
        raise TypeError("输入的不是列表")
    count = {}
    for item in lst:
        count[item] = count.get(item, 0) + 1
    return max(count, key=count.get)


# 异常列表项摘取
def clean_list(lst):
    """
    这个函数清理列表中的异常项，并返回一个新的列表。
    列表中的异常项包括：空值、类型不同于大部分元素的值。
    :param lst（list）：要清理的列表。
    :return list：清理后的列表。
    """
    # 确定列表中大部分元素的类型
    type_counter = {}
    for item in lst:
        if type(item) not in type_counter:
            type_counter[type(item)] = 1
        else:
            type_counter[type(item)] += 1
    most_common_type = max(type_counter, key=type_counter.get)

    # 过滤类型不同于大部分元素的值，和空值
    return [item for item in lst if isinstance(item, most_common_type) and bool(item)]
